package com.nwpu.hass.controller;

import com.nwpu.hass.domain.AuthEntity;
import com.nwpu.hass.domain.JsonRequest.ModifidyPermissionRequestBody;
import com.nwpu.hass.domain.JsonRequest.UserLoginRequestBody;
import com.nwpu.hass.domain.JsonRequest.UserRegisterRequestBody;
import com.nwpu.hass.domain.JsonResponse.FaceLoginResponse;
import com.nwpu.hass.domain.JsonResponse.FakeLoginResponse;
import com.nwpu.hass.domain.str2json.facematchjson.JsonRootBean;
import com.nwpu.hass.domain.JsonResponse.LogInResponse;
import com.nwpu.hass.domain.UserEntity;
import com.nwpu.hass.domain.str2json.faceregisterjson.RootBean;
import com.nwpu.hass.service.RedisService;
import com.nwpu.hass.service.UserService;
import com.nwpu.hass.serviceimpl.AuthService;
import com.nwpu.hass.serviceimpl.FaceService;
import com.nwpu.hass.serviceimpl.IdentifyService;
import com.nwpu.hass.utils.Code;
import com.nwpu.hass.utils.EmailSender;
import com.nwpu.hass.utils.FileComponent;
import com.nwpu.hass.utils.MyResponseEntity;
import com.nwpu.hass.utils.faceutils.Base64Util;
import com.nwpu.hass.utils.faceutils.GsonUtils;
import com.nwpu.hass.utils.faceutils.MultipartFileToFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;

import org.springframework.beans.BeanUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping("user")
public class UserController {

    @Resource
    private UserService userService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IdentifyService identifyService;

    @Autowired
    private EmailSender emailSender;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss");

    public static final double STANDARD_SCORE = 85;

    @Resource
    FileComponent fileComponent;

    @PostMapping("register")
    public MyResponseEntity<Object> addUser(@RequestBody @Validated UserRegisterRequestBody user) throws Exception {
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(user,userEntity);

        //先用code获取openId，再将openId赋给entity存入数据库
        String openId = userService.getOpenId(userEntity.getWechatAccount());
        log.info("用户openId已获取:" + openId);
        userEntity.setWechatAccount(openId);

        UserEntity userExist = userService.getUserByUsername(user.getUsername());
        if(Objects.isNull(userExist)){
            userEntity.setRecord(new Timestamp(System.currentTimeMillis()));
            userService.addUser(userEntity);
            String token = identifyService.signJwt(new AuthEntity(userEntity.getUserid(),userEntity.getMrole(),"##WeChat"));
            return new MyResponseEntity<>(Code.OK,token);
        }
        return new MyResponseEntity<>(Code.ERROR,"用户名已经存在",null);
    }

    @PostMapping("login")
    public MyResponseEntity<Object> login(@RequestBody @Valid UserLoginRequestBody request){
        UserEntity user = userService.getUserByUsername(request.getUsername());
        if(Objects.isNull(user)){
            return new MyResponseEntity<>(Code.ERROR,"用户名不存在",null);
        }else if(!request.getMpassword().equals(user.getMpassword())){
            return new MyResponseEntity<>(Code.ERROR,"用户密码错误",null);
        }else{
            log.info("用户已成功登陆");
            // 生成用户的token
            String token = identifyService.signJwt(new AuthEntity(user.getUserid(),user.getMrole(),"##WeChat"));
            return new MyResponseEntity<>(Code.OK,new LogInResponse(token,user.getMrole()!=2));
        }
    }

    @PostMapping("modifyUserPermission")
    public MyResponseEntity<Object> modifyUserPerssion(@RequestBody @Valid ModifidyPermissionRequestBody request){
        UserEntity user = userService.getUserById(request.getUserId());
        if(Objects.isNull(user)){
            return new MyResponseEntity<>(Code.ERROR,"该用户id不存在",null);
        }
        // mrole采用int形式存储，这个int的范围需要验证
        user.setMrole(request.getModifiedPermission());
        user.setRecord(new Timestamp(System.currentTimeMillis()));
        userService.modifiedUser(user);
        return new MyResponseEntity<>(Code.OK);
    }

    @GetMapping("deleteUser")
    public MyResponseEntity<Object> deleteUser(@RequestParam(value = "userId",required = true) Long userId){
        UserEntity userEntity = userService.getUserById(userId);
        if(Objects.isNull(userEntity)){
            return new MyResponseEntity<>(Code.ERROR,"该用户id不存在",null);
        }

        boolean result = userService.deleteUser(userEntity);
        if(result){
            log.info("用户已成功删除" + "用户ID为" + userId);
            return new MyResponseEntity(null);
        }else{
            return new MyResponseEntity<>(Code.ERROR,"用户还有申请设备或占用设备",null);
        }
    }

    @PostMapping("/face/register")
    public MyResponseEntity<Object> registerFace(@RequestParam(value = "username") String username, @RequestParam("file") MultipartFile file) throws Exception {
        String accessToken = AuthService.getAuth();
        UserEntity userEntity = userService.getUserByUsername(username);
        if(Objects.isNull(userEntity)){
            return new MyResponseEntity<>(Code.ERROR,"用户名不存在",null);
        }
        File imageFile = MultipartFileToFileUtil.multipartFileToFile(file);
        FileInputStream fileInputStream = new FileInputStream(imageFile);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        // 使用一个输入流从buffer里把数据读取出来
        while ((len = fileInputStream.read(buffer)) != -1) {
            // 用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outputStream.write(buffer, 0, len);
        }
        // 对字节数组Base64编码
        String imageStr = Base64Util.encode(outputStream.toByteArray());
        String result =  FaceService.add(imageStr,userEntity.getUserid(),accessToken);
        fileInputStream.close();
        imageFile.delete();
        RootBean rootBean = GsonUtils.fromJson(result, RootBean.class);
        String errorMessage = rootBean.getError_msg();
        if(errorMessage.equals("SUCCESS")){
            log.info("人脸数据录入成功");
            String token = identifyService.signJwt(new AuthEntity(userEntity.getUserid(),userEntity.getMrole(),"##WeChat"));
            return new MyResponseEntity<>(Code.OK,"人脸数据录入成功",token);
        }
        return new MyResponseEntity<>(Code.ERROR,"人脸数据录入失败","错误原因:"+errorMessage);
    }

    @PostMapping("face/login")
    public MyResponseEntity<Object> faceLogin(@RequestParam(value = "file") MultipartFile file) throws Exception{
        String accessToken = AuthService.getAuth();
        File imageFile = MultipartFileToFileUtil.multipartFileToFile(file);
        FileInputStream fileInputStream = new FileInputStream(imageFile);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        // 使用一个输入流从buffer里把数据读取出来
        while ((len = fileInputStream.read(buffer)) != -1) {
            // 用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outputStream.write(buffer, 0, len);
        }
        // 对字节数组Base64编码
        String imageStr = Base64Util.encode(outputStream.toByteArray());
        String result =  FaceService.faceMatch(imageStr,accessToken);
        JsonRootBean rootBean = GsonUtils.fromJson(result,JsonRootBean.class);
        fileInputStream.close();
        imageFile.delete();
        if(rootBean.getError_msg().equals("SUCCESS")){
            double score=rootBean.getResult().getUser_list().get(0).getScore();
            if(score>= STANDARD_SCORE){
                long userId = Long.parseLong(rootBean.getResult().getUser_list().get(0).getUser_id());
                UserEntity userEntity = userService.getUserById(userId);
                String token = identifyService.signJwt(new AuthEntity(userEntity.getUserid(),userEntity.getMrole(),"##WeChat"));
                log.info("人脸登陆成功");
                return new MyResponseEntity<>(Code.OK, new FaceLoginResponse(userEntity.getUsername(), token, userEntity.getMrole() != 2));
            }
            return new MyResponseEntity<>(Code.BAD_OPERATION,"用户图像不匹配","检查是否录入人脸信息或稍后重试");
        }else{
            return new MyResponseEntity<>(Code.BAD_OPERATION,"检查人脸图片",rootBean.getError_msg());
        }
    }

    @GetMapping("/userlist")
    public MyResponseEntity<Object> getUserList(@RequestParam("pageNo") int pageNo){
        log.info("用户列表已获取");
        return new MyResponseEntity<>(userService.getAllUser(pageNo*10-10,10));
    }

    @GetMapping("/userinfo")
    public MyResponseEntity<Object> getUserInfo(@RequestParam("username") String username){
        UserEntity userEntity = userService.getUserByUsername(username);
        if(Objects.isNull(userEntity)){
            return new MyResponseEntity<>(Code.BAD_OPERATION,"该用户不存在");
        }
        return new MyResponseEntity<>(userEntity);
    }

    @PostMapping("/modifyuser")
    public MyResponseEntity<Object> modifyUserInfo(@RequestHeader("token") String token,@RequestBody UserEntity userEntity){
        // 检查是否修改了userId,主要是防止利用接口软件恶意修改
        Long userId = redisService.getUserId(token);
        if(userId!=userEntity.getUserid()){
            return new MyResponseEntity<>(Code.BAD_OPERATION,"不允许修改userId");
        }
        // 检查用户名是否重复
        UserEntity user = userService.getUserByUsername(userEntity.getUsername());
        if(!Objects.isNull(user) && user.getUserid()!= userEntity.getUserid()){
            return new MyResponseEntity<>(Code.BAD_OPERATION,"该用户名已经存在");
        }
        // 检查是否修改了mrole,主要也是防止接口软件恶意修改
        UserEntity checkRole = userService.getUserById(userEntity.getUserid());
        if(checkRole.getMrole() !=userEntity.getMrole()){
            return new MyResponseEntity<>(Code.BAD_OPERATION,"不允许修改用户权限");
        }
        userService.modifiedUser(userEntity);
        log.info("用户信息已修改");
        return new MyResponseEntity<>(null);
    }

    @GetMapping("info")
    public MyResponseEntity<Object> fakeLogin(@RequestHeader("token") String token){
        Long userId = redisService.getUserId(token);
        String username = userService.getUserById(userId).getUsername();
        log.info("用户信息已获取");
        return new MyResponseEntity<>(new FakeLoginResponse(
               " ['editor']","I am a super administrator",
                "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
                username
        ));
    }
}
